package dk.au.cs.bdsi.core.representation;

import java.io.ByteArrayInputStream;
import java.io.StringWriter;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;


public abstract class CoreRepresentation<T extends CoreLink> {
	public static final String SELF_REL_VALUE = "self";
	
	private List<T> links;
	
	protected List<T> getLinks() {
		return links;
	}
	
	protected void setLinks(List<T> links) {
		this.links = links;
	}
	
	/**
     * Retrieve a link (if any) by its relation (rel) value.
     * 
     * @param relName Name of relation
     * @return Link or null if no such link exists
     */
    public T getLinkByName(String relName) {
        if (links == null) {
            return null;
        }

        for (T l : links) {
            if (l.getRelValue().toLowerCase().equals(relName.toLowerCase())) {
                return l;
            }
        }
        return null;
    }
	
	/**
     * Unmarshalls a XML representation to a object instance of the given type.
     * 
     * @param <E> Type of domain object
     * @param xml XML representation
     * @param type Class descriptor of domain object
     * @return Domain object instance with state of XML representation
     * @throws InvalidRepresentationException If unable to unmarshall or convert to given type
     */
    public final static <E> E unmarshal(String xml, Class<? extends E> type) 
    	throws InvalidRepresentationException {
    	try {
    		JAXBContext context = JAXBContext.newInstance(type);
    		Unmarshaller unmarshaller = context.createUnmarshaller();
    		Object o = unmarshaller.unmarshal(new ByteArrayInputStream(xml.getBytes()));
    		return type.cast(o);
    	} catch (JAXBException e) {
    		throw new InvalidRepresentationException("Unable to unmarshal representation", e);
    	} catch (ClassCastException e) {
    		throw new InvalidRepresentationException("Unable to convert to type", e);
    	} catch (Exception e) {
    		throw new InvalidRepresentationException(e);
    	}
    }
    
    /**
     * Marshalls a domain object instance of the given type to a XML representation.
     *  
     * @param <E> Type of domain object
     * @param object Domain object instance
     * @return XML representation of domain object
     * @throws InvalidRepresentationException If unable to marshall
     */
    public final static <E> String marshall(E object)
    	throws InvalidRepresentationException {
    	try {
    		JAXBContext context = JAXBContext.newInstance(object.getClass());
    		Marshaller marshaller = context.createMarshaller();
    		
    		StringWriter writer = new StringWriter();
    		marshaller.marshal(object, writer);
    		
    		return writer.toString();
    	} catch (JAXBException e) {
    		throw new InvalidRepresentationException("Unable to marshal representation", e);
    	} catch (Exception e) {
    		throw new InvalidRepresentationException(e);
    	}
    }
}
